//
// Created by kriko on 2021/6/22.
//

#ifndef ASIO_NET_ASIO_ADAPTING_H
#define ASIO_NET_ASIO_ADAPTING_H

#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <asio.hpp>

namespace net {
    template<typename SyncReadStream>
    class AsioInputStream : public google::protobuf::io::CopyingInputStream {
    public:
        AsioInputStream(SyncReadStream &sock);

        int Read(void *buffer, int size) override;
    private:
        SyncReadStream &_sock;
    };

    template<typename SyncReadStream>
    AsioInputStream<SyncReadStream>::AsioInputStream(SyncReadStream &sock) : _sock(sock) {

    }

    template<typename SyncReadStream>
    int AsioInputStream<SyncReadStream>::Read(void *buffer, int size) {
        std::size_t bytes_read;
        std::error_code ec;
        bytes_read = _sock.read_some(asio::buffer(buffer, size), ec);

        if (!ec) {
            return bytes_read;
        } else if (ec == asio::error::eof) {
            return 0;
        } else {
            return -1;
        }
    }

    template <typename SyncWriteStream>
    class AsioOutputStream : public google::protobuf::io::CopyingOutputStream {
    public:
        AsioOutputStream(SyncWriteStream& sock);

        bool Write(const void* buffer, int size) override;


    private:
        SyncWriteStream& _sock;
    };

    template <typename SyncWriteStream>
    AsioOutputStream<SyncWriteStream>::AsioOutputStream(SyncWriteStream &sock):_sock(sock) {

    }

    template <typename SyncWriteStream>
    bool AsioOutputStream<SyncWriteStream>::Write(const void *buffer, int size) {
        std::error_code ec;
        _sock.write_some(asio::buffer(buffer, size), ec);
        return !ec;
    }
}

#endif //ASIO_NET_ASIO_ADAPTING_H
